package com.athena.framework.web;

import com.athena.util.RedisClient;
import com.athena.util.SerializeUtil;
import org.apache.catalina.Manager;
import org.apache.catalina.session.StandardSession;

import java.io.Serializable;
import java.security.Principal;
import java.util.HashMap;


public class RedisSession extends StandardSession implements Serializable {
    protected static Boolean manualDirtyTrackingSupportEnabled = false;

    public static void setManualDirtyTrackingSupportEnabled(Boolean enabled) {
        manualDirtyTrackingSupportEnabled = enabled;
    }

    protected static String manualDirtyTrackingAttributeKey = "__changed__";

    public static void setManualDirtyTrackingAttributeKey(String key) {
        manualDirtyTrackingAttributeKey = key;
    }


    protected HashMap<String, Object> changedAttributes;
    protected Boolean dirty;

    protected transient RedisClient redisClient;

    private static String key = "athena:session:";

    public RedisSession(Manager manager) {
        super(manager);
        resetDirtyTracking();
    }

    public Boolean isDirty() {
        return dirty || !changedAttributes.isEmpty();
    }

    public HashMap<String, Object> getChangedAttributes() {
        return changedAttributes;
    }

    public void resetDirtyTracking() {
        changedAttributes = new HashMap<String, Object>();
        dirty = false;
        commit();
    }

    @Override
    public void setAttribute(String key, Object value) {
        if (manualDirtyTrackingSupportEnabled && manualDirtyTrackingAttributeKey.equals(key)) {
            dirty = true;
            return;
        }

        Object oldValue = getAttribute(key);
        if (value == null && oldValue != null
                || oldValue == null && value != null
                || !value.getClass().isInstance(oldValue)
                || !value.equals(oldValue)) {
            changedAttributes.put(key, value);
        }

        super.setAttribute(key, value);

        commit();
    }

    @Override
    public void removeAttribute(String name) {
        dirty = true;
        super.removeAttribute(name);
        commit();
    }

    @Override
    public void setId(String id) {
        this.id = id;
    }

    @Override
    public void setPrincipal(Principal principal) {
        dirty = true;
        super.setPrincipal(principal);
        commit();
    }

    public void commit() {
        if (getId() == null) {
            return;
        }
        if (redisClient == null) {
            redisClient = new RedisClient();
        }
        redisClient.setValue((key + getId()).getBytes(), SerializeUtil.serialize(this));
    }
}
